package com.own.component.common.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * AbstractListMapModel
 *
 * @author chenxueli
 * @date 2020/12/2 8:54
 */
@Slf4j
@NoArgsConstructor
public abstract class AbstractListMapModel<T, KEY> {

    /**
     * 列表
     */
    @Getter
    private java.util.List<T> list;

    /**
     * key的规则
     */
    private Function<? super T, KEY> keyExtractor;

    /**
     * 构造方法
     *
     * @param list         原列表
     * @param keyExtractor 指定的key
     */
    public AbstractListMapModel(java.util.List<T> list, Function<? super T, KEY> keyExtractor) {
        this.list = list;
        this.keyExtractor = keyExtractor;
    }

    /**
     * 获取某个键的值
     *
     * @param key 键
     * @return 值
     */
    abstract T get(KEY key);

    /**
     * 获取某个键的值
     *
     * @param key 键
     * @return 值
     */
    abstract java.util.List<T> list(KEY key);

    /**
     * 获取所有的键
     *
     * @return 键的列表
     */
    abstract Set<KEY> keys();

    /**
     * 追加数据
     *
     * @param item 数据对象
     */
    abstract void put(T item);

    /**
     * 追加数据
     *
     * @param list 数据对象列表
     */
    abstract void putAll(java.util.List<T> list);

    /**
     * 是否存在key
     *
     * @param key 键
     * @return 是否存在
     */
    abstract boolean containsKey(KEY key);

    public static class Object<T, KEY> extends AbstractListMapModel<T, KEY> {

        /**
         * map对象
         */
        private final Map<KEY, T> map;

        /**
         * 构造方法
         *
         * @param list         原列表
         * @param keyExtractor 指定的key
         */
        public Object(java.util.List<T> list, Function<? super T, KEY> keyExtractor) {
            super(list, keyExtractor);
            final var maxSize = (int) Math.round(list.size() * 0.75);
            this.map = new HashMap<>(maxSize);
            list.forEach(item -> {
                var key = super.keyExtractor.apply(item);
                this.map.putIfAbsent(key, item);
            });
        }

        /**
         * 获取某个键的值
         *
         * @param key 键
         * @return 值
         */
        @Override
        public T get(KEY key) {
            return this.map.get(key);
        }

        /**
         * 获取某个键的值
         *
         * @param key 键
         * @return 值
         */
        @Override
        public java.util.List<T> list(KEY key) {
            return null;
        }

        /**
         * 获取所有的键
         *
         * @return 键的列表
         */
        @Override
        public Set<KEY> keys() {
            return this.map.keySet();
        }

        /**
         * 追加数据
         *
         * @param item 数据对象
         */
        @Override
        public void put(T item) {
            super.getList().add(item);
            var key = super.keyExtractor.apply(item);
            this.map.putIfAbsent(key, item);
        }

        /**
         * 追加数据
         *
         * @param list 数据对象列表
         */
        @Override
        public void putAll(java.util.List<T> list) {
            super.getList().addAll(list);
            list.forEach(item -> {
                var key = super.keyExtractor.apply(item);
                this.map.putIfAbsent(key, item);
            });
        }

        /**
         * 是否存在key
         *
         * @param key 键
         * @return 是否存在
         */
        @Override
        public boolean containsKey(KEY key) {
            return this.map.containsKey(key);
        }

    }

    static class List<T, KEY> extends AbstractListMapModel<T, KEY> {
        /**
         * 列表map对象
         */
        private final Map<KEY, java.util.List<T>> map;

        /**
         * 构造方法
         *
         * @param list         原列表
         * @param keyExtractor 指定的key
         */
        public List(java.util.List<T> list, Function<? super T, KEY> keyExtractor) {
            super(list, keyExtractor);
            final var maxSize = (int) Math.round(list.size() * 0.75);
            this.map = new HashMap<>(maxSize);
            list.forEach(item -> {
                var key = super.keyExtractor.apply(item);
                if (!this.map.containsKey(key)) {
                    this.map.put(key, new ArrayList<>());
                }
                this.map.get(key).add(item);
            });
        }

        /**
         * 获取某个键的值
         *
         * @param key 键
         * @return 值
         */
        @Override
        public T get(KEY key) {
            return null;
        }

        /**
         * 获取某个键的值
         *
         * @param key 键
         * @return 值
         */
        @Override
        public java.util.List<T> list(KEY key) {
            return this.map.get(key);
        }

        /**
         * 获取所有的键
         *
         * @return 键的列表
         */
        @Override
        public Set<KEY> keys() {
            return this.map.keySet();
        }

        /**
         * 追加数据
         *
         * @param item 数据对象
         */
        @Override
        public void put(T item) {
            super.getList().add(item);
            var key = super.keyExtractor.apply(item);
            if (!this.map.containsKey(key)) {
                this.map.put(key, new ArrayList<>());
            }
            this.map.get(key).add(item);
        }

        /**
         * 追加数据
         *
         * @param list 数据对象列表
         */
        @Override
        public void putAll(java.util.List<T> list) {
            list.forEach(this::put);
        }

        /**
         * 是否存在key
         *
         * @param key 键
         * @return 是否存在
         */
        @Override
        public boolean containsKey(KEY key) {
            return this.map.containsKey(key);
        }
    }

}
